

#include "src/net/EventLoopThread.h"

#include "src/net/EventLoop.h"

#include <mutex>

using namespace sola;
using namespace sola::net;

EventLoopThread::EventLoopThread(const ThreadInitCallback& cb, const std::string& name)
    : loop_(NULL)
    , exiting_(false)
    ,
    // thread_(std::bind(&EventLoopThread::threadFunc, this), name),
    mutex_()
    , cond_()
    , callback_(cb) {
}

EventLoopThread::~EventLoopThread() {
    exiting_ = true;
    if (loop_ != NULL) // not 100% race-free, eg. threadFunc could be running callback_.
    {
        // still a tiny chance to call destructed object, if threadFunc exits just now.
        // but when EventLoopThread destructs, usually programming is exiting anyway.
        loop_->quit();
        thread_.join();
    }
}

EventLoop* EventLoopThread::startLoop() {
    //   assert(!thread_.started());
    //   thread_.start();
    thread_ = std::thread(std::bind(&EventLoopThread::threadFunc, this));

    EventLoop* loop = NULL;
    {
        std::unique_lock<std::mutex> lock(mutex_);
        while (loop_ == NULL) {
            //   cond_.wait();
            cond_.wait(lock, [this] { return loop_ != NULL; });
        }
        loop = loop_;
    }

    return loop;
}

void EventLoopThread::threadFunc() {
    EventLoop loop;

    if (callback_) {
        callback_(&loop);
    }

    {
        std::lock_guard<std::mutex> lock(mutex_);
        loop_ = &loop;
        cond_.notify_one();
    }

    loop.loop();
    std::lock_guard<std::mutex> lock(mutex_);
    loop_ = NULL;
}
